#include <easy_sock.h>
#include <thread_pool.h>
#include <mfile.h>
#include <mlog.h>
#include <demo.h>
#include <appdef.h>

#define PORT 1234
#define INIT_THREAD_NUM 10

int main()
{
    int sfd,cfd;
    unsigned int addr_len;
    struct sockaddr_in cli_addr;
    int n=3;
    MSOCK *msock;

    int jobs[10];

    /*open a listen port*/
    if( (sfd=open_listen(PORT)) == -1 )
    {
        mlog("demo.log", _FL_, "open port[%d] failed!", PORT);
        return -1;
    }
    mlog("demo.log", _FL_, "demo start listen on port:%d", PORT);
    memset( &cli_addr, 0x00, sizeof(struct sockaddr_in) );
    
    /*init thread pool*/
    pool_init(INIT_THREAD_NUM);

    mlog("demo.log", _FL_, "thread_init succ");
    /*loop to get connection*/
    addr_len = sizeof( struct sockaddr_in);
    while(1)
    {
        memset( &cli_addr, 0x00, sizeof(struct sockaddr) );
        if((cfd=accept( sfd, (struct sockaddr *)(&cli_addr), &addr_len)) == -1)
        {
            mlog( "demo.log", _FL_, "get connection failed!");
            perror("accept");
            continue;   
        }
        mlog("demo.log", _FL_, "get connection from %s",inet_ntoa(cli_addr.sin_addr) );
        /*start 2 jobs to process socket*/
        init_msock( cfd, &msock);
        /*pool_add_job( sock_recv, (void *)msock);*/
        pool_add_job( sock_recv, (void *)msock);
        pool_add_job( sock_send, (void *)msock);
    }
    pool_destroy();
    printf( "process end\n" );
}

void * sock_send(void *arg)
{
    MSOCK *msock;
    RS rs;
    FINFO fi;
    int num=0;
    char rbuf[2000];

    msock = (MSOCK *)arg;
    msock->sflag++;
    mlog( "demo.log", _FL_, "do sock_send by thread %lu", pthread_self() );

    while( (msock->rflag==1) || (msock->length>0) )
    {
        if( msock->length > 0 )
        {
            pthread_mutex_lock( &(msock->buf_lock) );
            mlog( "demo.log", _FL_, "ready to send buf");
            
                /*analysis response*/
  /*  memset( &rs, 0x00, sizeof(RS) );
    memcpy( &rs, msock->sbuf, sizeof(RS) );
    if( rs.code == M_FAIL )
    {
        printf("request failed! msg[%s]\n", rs.msg);
    }
    else
    {
        memset( &fi, 0x00, sizeof(FINFO) );
        memcpy( &fi, rs.msg, sizeof(FINFO) );
        printf("get file info: filename[%s] file_len[%lu]\n", fi.f_name, fi.f_size);
    }
*/    

            num=send( msock->sock_fd, msock->sbuf, msock->length, 0 );
            if( num == -1 )
            {
                perror("send");
                mlog( "demo.log", _FL_, "send msg failed" );
            }
            else if(num == msock->length )
            {
                mlog( "demo.log", _FL_, "send %d byte(s)", num );
                msock->length = 0;
                memset( msock->sbuf, 0x00, sizeof(msock->sbuf) );
            }
            mlog( "demo.log", _FL_, "buffer len msock->length[%d]", msock->length );
            pthread_mutex_unlock( &(msock->buf_lock) ); 
        }  
    }

    msock->sflag--;
    mlog("demo.log", _FL_, "send proces ready to exit rflag[%d]", msock->sflag);
    return NULL;
}

void * sock_recv(void *arg)
{
    char rbuf[2048];
    RQ rq;
    RS rs;
    MSOCK *msock;
    int length;
    int sock_fd;
    int num=0;
    unsigned long int fnum;
    SFILE sf;
    FINFO fi;

    msock = (MSOCK *)arg;
    msock->rflag++;
    /*sock_fd = *(int *)arg;*/

    while(1)
    {
        memset( &rq, 0x00, sizeof(RQ) );
        memset( rbuf, 0x00, sizeof(rbuf) );
        
        num=recv( msock->sock_fd, rbuf, sizeof(rbuf), 0 );
        if( num == -1)
        {
            perror("recv");
            return NULL;
        }
        mlog("demo.log", _FL_, "get string:%s", rbuf );
/*        
        num=recv( sock_fd, rbuf, sizeof(rq), 0 );
        if( num == -1)
        {
            perror("recv");
            return NULL;
        }*/
        mlog("demo.log", _FL_, "get %d bytes", num );
        
        /*format string buffer to struct*/
        memcpy( &rq, rbuf, sizeof(RQ) );
        mlog("demo.log", _FL_, "get request:rq_name[%s] rq_str[%s]", rq.rq_name, rq.rq_str );
        
        /*request of get file*/
        if( strcmp( rq.rq_name, "GETFILE") == 0 )
        {
            memset( &rs, 0x00, sizeof(RS) );
            memset( &sf, 0x00, sizeof(SFILE) );
            memset( &fi, 0x00, sizeof(FINFO) );
            mlog("demo.log", _FL_, "get a request of GETFILE %s", rq.rq_str );
            if( get_fileinfo(rq.rq_str, &fi) != M_OK )
            {
                /*failed to get file*/
                rs.code = M_FAIL;
                strcpy( rs.msg, "file not found" );
                mlog("demo.log", _FL_, "bad GETFILE filename[%s]", rq.rq_str );
            }
            else
            {
                rs.code = M_OK;
                mlog("demo.log", _FL_, "f_name[%s] f_size[%lu]", fi.f_name, fi.f_size );
                mlog( "demo.log", _FL_, "msg%d finfo%d", sizeof(rs.msg), sizeof(FINFO) );
                assert( sizeof(rs.msg) >= sizeof(FINFO) );
                memcpy( rs.msg, &fi, sizeof(FINFO) );
            }
            memcpy( msock->sbuf, &rs, sizeof(RS) );
            msock->length = sizeof(RS);
            mlog("demo.log", _FL_, "create send msg end" );
            break;
        }
        
        /*request of termilate connection*/
        else if( strcmp( rq.rq_name, "QUIT") == 0 )
        {
            memset( &rs, 0x00, sizeof(RS) ); 
            rs.code = M_OK;
            strcpy(rs.msg, "ready to close connection");
            break;
        }
        
        /*unknow request*/
        else
        {
            memset( &rs, 0x00, sizeof(RS) ); 
            rs.code = M_FAIL;
            strcpy(rs.msg, "unkonwn request type");
            continue;
        }
    }

     assert( sizeof(msock->sbuf) >= sizeof(RS) );
     pthread_mutex_lock( &(msock->buf_lock) );
     mlog("demo.log", _FL_, "put msg to buf" );
     memcpy( msock->sbuf, &rs, sizeof(RS));
     
     /*for test*/
     /*memset( &rs, 0x00, sizeof(RS) );
     memcpy(&rs, msock->sbuf, sizeof(RQ) );
     mlog( "demo.log", _FL_, "code[%d]", rs.code );
     memset( &fi, 0x00, sizeof(FINFO) );
     memcpy( &fi, rs.msg, sizeof(FINFO) );
     mlog( "demo.log", _FL_, "filename[%s], filelen[%lu]", fi.f_name, fi.f_size );
     */
     msock->length = sizeof(RQ);
     mlog("demo.log", _FL_, "put msg to buf end" );
     pthread_mutex_unlock( &(msock->buf_lock) );  
     
     /*begin to send file*/
     mlog( "demo.log", _FL_, "begin to send file msock->length[%d]", msock->length );
     fnum = 0;
     fnum = send_file( msock, rq.rq_str, fi.f_size );
     if( fnum == fi.f_size )
     {
        mlog("demo.log", _FL_, "send file succ" );
     }   
     
     msock->rflag--;
     mlog("demo.log", _FL_, "read proces ready to exit rflag[%d]", msock->rflag);
     close_sock(msock);
     msock = NULL;
     return NULL;
}

int send_file( MSOCK *msock, char *filepathname, int file_len )
{
    int num;
    int len;
    int ret;
    FILE *fp;
    
    if( (fp=fopen( filepathname, "rb" )) == NULL )
    {
        mlog("demo.log", _FL_, "open file[%s] failed", filepathname );
        return -1;
    }
    
    /*read file and put read content into send buffer*/
    /*num use to calculate send bytes*/
    num = 0;
    mlog( "demo.log", _FL_, "begin to send file[%s] f_size[%d]", filepathname,file_len );
    while( 1 )
    {
        if(!feof(fp) && (msock->length==0))
        {
            pthread_mutex_lock( &(msock->buf_lock) );
            memset( msock->sbuf, 0x00, sizeof(msock->sbuf) );
            len=fread( msock->sbuf, 1, sizeof(msock->sbuf), fp );
            msock->length = len;
            mlog("demo.log", _FL_, " read file[%d] buf_len[%d]", num, msock->length );
            num += len;
            mlog("demo.log", _FL_, " read file[%d]", num );
            pthread_mutex_unlock( &(msock->buf_lock) );
            if( file_len == num )
            {
                break;
            }
        }
    }

    /*clsoe file handle*/
    close(fp);
    mlog("demo.log", _FL_, "file[%s] send end!", filepathname );
    return num;
}